﻿#pragma once

#include <learn/utils/json.h>

#define REFLECT_PP_FOREACH_1(f, _1) f(_1)
#define REFLECT_PP_FOREACH_2(f, _1, _2) f(_1) f(_2)
#define REFLECT_PP_FOREACH_3(f, _1, _2, _3) f(_1) f(_2) f(_3)
#define REFLECT_PP_FOREACH_4(f, _1, _2, _3, _4) f(_1) f(_2) f(_3) f(_4)
#define REFLECT_PP_FOREACH_5(f, _1, _2, _3, _4, _5) f(_1) f(_2) f(_3) f(_4) f(_5)
#define REFLECT_PP_FOREACH_6(f, _1, _2, _3, _4, _5, _6) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6)
#define REFLECT_PP_FOREACH_7(f, _1, _2, _3, _4, _5, _6, _7) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7)
#define REFLECT_PP_FOREACH_8(f, _1, _2, _3, _4, _5, _6, _7, _8) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8)
#define REFLECT_PP_FOREACH_9(f, _1, _2, _3, _4, _5, _6, _7, _8, _9)                                                    \
    f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9)
#define REFLECT_PP_FOREACH_10(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10)                                              \
    f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10)
#define REFLECT_PP_FOREACH_11(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11)                                         \
    f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)
#define REFLECT_PP_FOREACH_12(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12)                                    \
    f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12)
#define REFLECT_PP_FOREACH_13(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13)                               \
    f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13)
#define REFLECT_PP_FOREACH_14(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14)                          \
    f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14)
#define REFLECT_PP_FOREACH_15(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15)                     \
    f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15)
#define REFLECT_PP_FOREACH_16(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16)                \
    f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16)

// 注意添加 /Zc:preprocessor 编译选项，否则 REFLECT_PP_NARGS 不能正确计算参数数量
#define REFLECT_PP_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
#define REFLECT_PP_NARGS(...) REFLECT_PP_NARGS_IMPL(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

// 多层嵌套展开求值
#define REFLECT_EXPAND_IMPL(...) __VA_ARGS__
#define REFLECT_EXPAND(...) REFLECT_EXPAND_IMPL(__VA_ARGS__)
#define REFLECT_CONCAT_IMPL(a, b) a##b
#define REFLECT_CONCAT(a, b) REFLECT_CONCAT_IMPL(a, b)

namespace xy
{

namespace utils
{

template <typename T> struct reflect_trait
{
    static constexpr bool has_members()
    {
        return requires(T t) { t.for_each_member(nullptr); };
    }

    template <class Func> constexpr static void for_each_member(const T &self, Func &&func)
    {
        const_cast<T &>(self).for_each_member(func);
    }
};

template <class T>
    requires(!reflect_trait<T>::has_members())
inline auto serialize(const T &obj)
{
    return json(obj);
}

template <class T>
    requires(reflect_trait<T>::has_members())
inline auto serialize(const T &obj)
{
    json data;
    reflect_trait<T>::for_each_member(obj,
                                      [&data](const auto &key, const auto &value) { data[key] = serialize(value); });
    return data;
}

template <class T>
    requires(!reflect_trait<T>::has_members())
inline void deserialize(const json &data, T &obj)
{
    using Ty = std::decay_t<T>;
    const_cast<Ty &>(obj) = data.as<Ty>();
}

template <class T>
    requires(reflect_trait<T>::has_members())
inline void deserialize(const json &data, T &obj)
{
    reflect_trait<T>::for_each_member(obj, [&data](const auto &key, auto &value) { deserialize(data[key], value); });
}

} // namespace utils

} // namespace xy

// 遍历展开 f(...)
#define REFLECT_PP_FOR_EACH(f, ...)                                                                                    \
    REFLECT_EXPAND(REFLECT_CONCAT(REFLECT_PP_FOREACH_, REFLECT_PP_NARGS(__VA_ARGS__))(f, __VA_ARGS__))

#define REFLECT_MEMBER(x) func(#x, x);
#define REFLECT_MEMBER_PTR(x) func(#x, &This::x);
#define REFLECT_TYPE_MEMBER(x) func(#x, self.x);

// 内部反射宏
#define REFLECT(...)                                                                                                   \
    template <class Func> constexpr void for_each_member(Func &&func) const                                            \
    {                                                                                                                  \
        REFLECT_PP_FOR_EACH(REFLECT_MEMBER, __VA_ARGS__)                                                               \
    }

// Type 已经具有 ()，因此 REFLECT_EXPAND 后面不用加 ()
#define REFLECT_TYPE_TEMPLATE_BEGIN(Type, ...)                                                                         \
    template <__VA_ARGS__> struct xy::utils::reflect_trait<REFLECT_EXPAND(REFLECT_EXPAND Type)>                        \
    {                                                                                                                  \
        using This = REFLECT_EXPAND(REFLECT_EXPAND Type);                                                              \
        static constexpr bool has_members()                                                                            \
        {                                                                                                              \
            return true;                                                                                               \
        }                                                                                                              \
        template <class Func> constexpr static void for_each_member(const This &cself, Func &&func)                    \
        {                                                                                                              \
            This &self = const_cast<This &>(cself);

#define REFLECT_TYPE_TEMPLATE_END()                                                                                    \
    }                                                                                                                  \
    }                                                                                                                  \
    ;

// 外部模板反射宏，Type 已经具有 ()，因此 REFLECT_TYPE_TEMPLATE_BEGIN 后面不用加 ()
#define REFLECT_TYPE_TEMPLATE(Type, ...)                                                                               \
    REFLECT_EXPAND(REFLECT_TYPE_TEMPLATE_BEGIN Type)                                                                   \
    REFLECT_PP_FOR_EACH(REFLECT_TYPE_MEMBER, __VA_ARGS__)                                                              \
    REFLECT_TYPE_TEMPLATE_END()

// 外部反射宏，由于 REFLECT_EXPAND(REFLECT_TYPE_TEMPLATE_BEGIN Type) 需要 Type 带 ()，因此需要加 ()
#define REFLECT_TYPE(Type, ...) REFLECT_TYPE_TEMPLATE(((Type)), __VA_ARGS__)

struct Student
{
    std::string name;
    int age;

    void to_string() const
    {
        std::cout << "name: " << name << ", age: " << age << std::endl;
    }

    REFLECT(name, age)
};

// REFLECT_TYPE(Student, name, age)

template <class T, class U> struct Baby
{
    std::string name;
    T cost;
    U age;
    Student parent{"Unknown", 0};
};

// 宏无法区分 <>，因此要保护逗号
REFLECT_TYPE_TEMPLATE(((Baby<T, U>), class T, class U), name, cost, age, parent)

std::string test()
{
    Student s{"Alice", 20};
    Baby<int, double> b{"Bob", 100, 3.14};
    auto ja = xy::utils::serialize(s);
    auto jb = xy::utils::serialize(b);
    xy::utils::deserialize(ja, s);
    xy::utils::deserialize(jb, b);
    return ja.dump() + "\n" + jb.dump();
}